/**
 * 算式继承体系测试类 - 版本2.0
 * 
 * 测试覆盖范围：
 * 1. 抽象类Expression的基础功能
 * 2. 加法算式AdditionExpression的特有功能
 * 3. 减法算式SubtractionExpression的特有功能
 * 4. 继承关系和多态性测试
 * 5. 边界情况和异常测试
 */
package edu.scut.oop.exercise.v2;

import java.util.HashSet;
import java.util.Set;

public class ExpressionTestV2 {
    private static int totalTests = 0;
    private static int passedTests = 0;
    
    /**
     * 主测试方法
     */
    public static void main(String[] args) {
        System.out.println("===== 算式继承体系测试 V2.0 =====");
        System.out.println("测试时间: " + new java.util.Date());
        System.out.println();
        
        testExpressionBasic();
        testAdditionExpression();
        testSubtractionExpression();
        testInheritanceAndPolymorphism();
        testExceptionHandling();
        
        System.out.println("\n===== 测试结果统计 =====");
        System.out.println("总测试数: " + totalTests);
        System.out.println("通过测试: " + passedTests);
        System.out.println("失败测试: " + (totalTests - passedTests));
        System.out.println("通过率: " + String.format("%.1f%%", (double)passedTests/totalTests*100));
        
        if (passedTests == totalTests) {
            System.out.println("\n🎉 所有测试通过！算式继承体系设计正确。");
        } else {
            System.out.println("\n❌ 有测试失败，需要检查代码实现。");
        }
    }
    
    // ========== 1. 抽象类基础功能测试 ==========
    private static void testExpressionBasic() {
        System.out.println("=== 1. 抽象类Expression基础功能测试 ===");
        
        test("Expression构造函数和基础属性", () -> {
            AdditionExpression addExpr = new AdditionExpression(30, 25);
            assertEquals(30, addExpr.getNum1(), "操作数1");
            assertEquals(25, addExpr.getNum2(), "操作数2");
            assertEquals(55, addExpr.getResult(), "计算结果");
        });
        
        test("Expression格式化输出", () -> {
            SubtractionExpression subExpr = new SubtractionExpression(80, 30);
            String exprStr = subExpr.formatExpression();
            String answerStr = subExpr.formatWithAnswer();
            
            assertEquals("80 - 30", exprStr, "格式化算式");
            assertEquals("80 - 30 = 50", answerStr, "格式化含答案");
        });
        
        test("Expression的equals和hashCode", () -> {
            AdditionExpression expr1 = new AdditionExpression(25, 35);
            AdditionExpression expr2 = new AdditionExpression(25, 35);
            AdditionExpression expr3 = new AdditionExpression(25, 36);
            
            assertTrue(expr1.equals(expr2), "相同算式应该相等");
            assertTrue(expr1.hashCode() == expr2.hashCode(), "相同算式hashCode应该相等");
            assertTrue(!expr1.equals(expr3), "不同算式不应该相等");
        });
    }
    
    // ========== 2. 加法算式特有功能测试 ==========
    private static void testAdditionExpression() {
        System.out.println("\n=== 2. 加法算式AdditionExpression特有功能测试 ===");
        
        test("AdditionExpression构造函数和计算", () -> {
            AdditionExpression addExpr = new AdditionExpression(40, 50);
            assertEquals("+", addExpr.getOperatorSymbol(), "加法操作符");
            assertTrue(addExpr.isAddition(), "isAddition返回true");
            assertTrue(!addExpr.isSubtraction(), "isSubtraction返回false");
            assertEquals(90, addExpr.calculate(), "加法计算");
        });
        
        test("AdditionExpression加法业务规则验证", () -> {
            // 正常的加法
            AdditionExpression validAdd = new AdditionExpression(45, 55);
            assertTrue(validAdd.isValid(), "正常加法应该有效");
            
            // 边界情况：等于100
            AdditionExpression maxAdd = new AdditionExpression(50, 50);
            assertTrue(maxAdd.isValid(), "结果等于100的加法应该有效");
            
            // 异常情况：超过100
            try {
                AdditionExpression invalidAdd = new AdditionExpression(60, 50);
                fail("创建结果超过100的加法应该抛出异常");
            } catch (IllegalArgumentException e) {
                assertTrue(e.getMessage().contains("不能超过100"), "异常消息应该包含业务规则");
            }
        });
        
        test("AdditionExpression操作数修改", () -> {
            AdditionExpression addExpr = new AdditionExpression(30, 40);
            
            // 正常修改
            addExpr.setNum1(20);
            assertEquals(60, addExpr.getResult(), "修改操作数1后的结果");
            
            // 异常修改：导致结果超过100
            try {
                addExpr.setNum1(70);
                fail("修改操作数导致结果超过100应该抛出异常");
            } catch (IllegalArgumentException e) {
                assertTrue(e.getMessage().contains("不能超过100"), "异常消息应该包含业务规则");
            }
        });
        
        test("AdditionExpression特有方法", () -> {
            AdditionExpression addExpr = new AdditionExpression(25, 35);
            String desc = addExpr.getDescription();
            assertTrue(desc.contains("加法算式"), "描述应该包含加法标识");
            assertTrue(desc.contains("25 + 35 = 60"), "描述应该包含完整算式");
            
            // 相似性测试
            AdditionExpression similarExpr = new AdditionExpression(30, 30);
            assertTrue(addExpr.isSimilarTo(similarExpr), "结果相同的加法算式应该相似");
        });
    }
    
    // ========== 3. 减法算式特有功能测试 ==========
    private static void testSubtractionExpression() {
        System.out.println("\n=== 3. 减法算式SubtractionExpression特有功能测试 ===");
        
        test("SubtractionExpression构造函数和计算", () -> {
            SubtractionExpression subExpr = new SubtractionExpression(80, 30);
            assertEquals("-", subExpr.getOperatorSymbol(), "减法操作符");
            assertTrue(!subExpr.isAddition(), "isAddition返回false");
            assertTrue(subExpr.isSubtraction(), "isSubtraction返回true");
            assertEquals(50, subExpr.calculate(), "减法计算");
        });
        
        test("SubtractionExpression减法业务规则验证", () -> {
            // 正常的减法
            SubtractionExpression validSub = new SubtractionExpression(80, 30);
            assertTrue(validSub.isValid(), "正常减法应该有效");
            
            // 边界情况：等于0
            SubtractionExpression zeroSub = new SubtractionExpression(50, 50);
            assertTrue(zeroSub.isValid(), "结果等于0的减法应该有效");
            
            // 异常情况：小于0
            try {
                SubtractionExpression invalidSub = new SubtractionExpression(30, 50);
                fail("创建结果小于0的减法应该抛出异常");
            } catch (IllegalArgumentException e) {
                assertTrue(e.getMessage().contains("不能小于0"), "异常消息应该包含业务规则");
            }
        });
        
        test("SubtractionExpression操作数修改", () -> {
            SubtractionExpression subExpr = new SubtractionExpression(80, 30);
            
            // 正常修改
            subExpr.setNum2(20);
            assertEquals(60, subExpr.getResult(), "修改操作数2后的结果");
            
            // 创建新的减法算式测试异常修改
            try {
                SubtractionExpression testExpr = new SubtractionExpression(20, 30);
                testExpr.setNum2(50); // 应该抛出异常
                fail("修改操作数导致结果小于0应该抛出异常");
            } catch (IllegalArgumentException e) {
                assertTrue(e.getMessage().contains("不能小于0"), "异常消息应该包含业务规则");
            }
        });
        
        test("SubtractionExpression特有方法", () -> {
            SubtractionExpression subExpr = new SubtractionExpression(80, 30);
            String desc = subExpr.getDescription();
            assertTrue(desc.contains("减法算式"), "描述应该包含减法标识");
            assertTrue(desc.contains("80 - 30 = 50"), "描述应该包含完整算式");
            
            // 交换操作数条件测试
            SubtractionExpression swapExpr = new SubtractionExpression(70, 20);
            assertTrue(swapExpr.canSwapOperands(), "应该可以交换操作数");
            
            // 测试交换操作数
            SubtractionExpression swapped = swapExpr.swapOperands();
            assertEquals(50, swapped.getResult(), "交换后的结果应该保持不变");
            assertTrue(swapped.isValid(), "交换后的算式应该有效");
            
            // 验证交换后的算式
            assertEquals("0 - (-50) = 50", swapped.formatWithAnswer(), "交换后的算式格式");
        });
    }
    
    // ========== 4. 继承关系和多态性测试 ==========
    private static void testInheritanceAndPolymorphism() {
        System.out.println("\n=== 4. 继承关系和多态性测试 ===");
        
        test("继承关系验证", () -> {
            AdditionExpression addExpr = new AdditionExpression(25, 35);
            SubtractionExpression subExpr = new SubtractionExpression(80, 30);
            
            assertTrue(addExpr instanceof Expression, "加法算式是Expression的实例");
            assertTrue(subExpr instanceof Expression, "减法算式是Expression的实例");
            assertTrue(addExpr instanceof AdditionExpression, "加法算式是AdditionExpression的实例");
            assertTrue(subExpr instanceof SubtractionExpression, "减法算式是SubtractionExpression的实例");
        });
        
        test("多态性测试", () -> {
            // 通过父类引用使用子类对象
            Expression expr1 = new AdditionExpression(30, 40);
            Expression expr2 = new SubtractionExpression(90, 30);
            
            assertTrue(expr1.isAddition(), "多态：加法算式的isAddition应该返回true");
            assertTrue(expr2.isSubtraction(), "多态：减法算式的isSubtraction应该返回true");
            assertEquals("30 + 40 = 70", expr1.formatWithAnswer(), "多态：格式化输出");
            assertEquals("90 - 30 = 60", expr2.formatWithAnswer(), "多态：格式化输出");
        });
        
        test("抽象方法重写验证", () -> {
            Expression addExpr = new AdditionExpression(25, 25);
            Expression subExpr = new SubtractionExpression(50, 25);
            
            // 验证不同子类的抽象方法实现
            assertEquals("+", addExpr.getOperatorSymbol(), "加法操作符");
            assertEquals("-", subExpr.getOperatorSymbol(), "减法操作符");
            assertEquals(50, addExpr.calculate(), "加法计算");
            assertEquals(25, subExpr.calculate(), "减法计算");
        });
    }
    
    // ========== 5. 异常处理测试 ==========
    private static void testExceptionHandling() {
        System.out.println("\n=== 5. 异常处理和边界情况测试 ===");
        
        test("加法边界值测试", () -> {
            // 最大值边界
            AdditionExpression maxExpr = new AdditionExpression(50, 50);
            assertTrue(maxExpr.isValid(), "结果为100的加法应该有效");
            
            // 负数加法
            AdditionExpression negativeAdd = new AdditionExpression(-50, 30);
            assertEquals(-20, negativeAdd.getResult(), "负数加法计算");
            assertTrue(negativeAdd.isValid(), "负数加法应该有效");
            
            // 超过100的异常
            testException("超过100的加法", () -> {
                new AdditionExpression(60, 50);
            }, IllegalArgumentException.class);
        });
        
        test("减法边界值测试", () -> {
            // 最小值边界
            SubtractionExpression minExpr = new SubtractionExpression(50, 50);
            assertTrue(minExpr.isValid(), "结果为0的减法应该有效");
            
            // 负数减法
            SubtractionExpression negativeSub = new SubtractionExpression(-30, -50);
            assertEquals(20, negativeSub.getResult(), "负数减法计算");
            assertTrue(negativeSub.isValid(), "负数减法应该有效");
            
            // 小于0的异常
            testException("小于0的减法", () -> {
                new SubtractionExpression(30, 50);
            }, IllegalArgumentException.class);
        });
        
        test("去重功能测试", () -> {
            Set<Expression> expressions = new HashSet<>();
            
            // 添加相同算式
            expressions.add(new AdditionExpression(25, 35));
            expressions.add(new AdditionExpression(25, 35));
            expressions.add(new SubtractionExpression(80, 20));
            
            assertEquals(2, expressions.size(), "应该能正确去重");
        });
    }
    
    // ========== 测试工具方法 ==========
    private static void test(String testName, TestRunnable test) {
        totalTests++;
        try {
            test.run();
            passedTests++;
            System.out.println("✅ " + testName);
        } catch (AssertionError e) {
            System.out.println("❌ " + testName + " - " + e.getMessage());
        } catch (Exception e) {
            System.out.println("❌ " + testName + " - 异常: " + e.getMessage());
        }
    }
    
    private static void testException(String testName, TestRunnable test, Class<? extends Exception> expectedType) {
        totalTests++;
        try {
            test.run();
            System.out.println("❌ " + testName + " - 应该抛出" + expectedType.getSimpleName() + "异常");
        } catch (Exception e) {
            if (expectedType.isInstance(e)) {
                passedTests++;
                System.out.println("✅ " + testName + " - 正确抛出" + expectedType.getSimpleName() + "异常");
            } else {
                System.out.println("❌ " + testName + " - 抛出了错误的异常类型: " + e.getClass().getSimpleName());
            }
        }
    }
    
    // ========== 断言方法 ==========
    private static void assertEquals(Object expected, Object actual, String message) {
        if (expected == null && actual == null) return;
        if (expected == null || !expected.equals(actual)) {
            throw new AssertionError(message + " - 期望: " + expected + ", 实际: " + actual);
        }
    }
    
    private static void assertEquals(int expected, int actual, String message) {
        if (expected != actual) {
            throw new AssertionError(message + " - 期望: " + expected + ", 实际: " + actual);
        }
    }
    
    private static void assertTrue(boolean condition, String message) {
        if (!condition) {
            throw new AssertionError(message + " - 条件应该为true");
        }
    }
    
    private static void fail(String message) {
        throw new AssertionError(message);
    }
    
    // 函数式接口
    @FunctionalInterface
    interface TestRunnable {
        void run() throws Exception;
    }
}